package com.shlh.saas.config;

import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.HikariPoolMXBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * HikariCP连接池监控配置
 * 用于监控Facebook数据库连接池状态，防止连接泄漏
 */
@Configuration
@EnableScheduling
@Slf4j
public class HikariCPMonitorConfig {

    /**
     * HikariCP连接池健康检查器
     */
    @Component
    public static class HikariCPHealthIndicator implements HealthIndicator {

        @Autowired
        private DataSource dataSource;

        @Override
        public Health health() {
            try {
                if (dataSource instanceof HikariDataSource) {
                    HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                    HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean();

                    Map<String, Object> details = new HashMap<>();
                    details.put("poolName", hikariDataSource.getPoolName());
                    details.put("activeConnections", poolMXBean.getActiveConnections());
                    details.put("idleConnections", poolMXBean.getIdleConnections());
                    details.put("totalConnections", poolMXBean.getTotalConnections());
                    details.put("threadsAwaitingConnection", poolMXBean.getThreadsAwaitingConnection());
                    details.put("maximumPoolSize", hikariDataSource.getMaximumPoolSize());
                    details.put("minimumIdle", hikariDataSource.getMinimumIdle());

                    // 计算连接池使用率
                    double usageRate = (double) poolMXBean.getActiveConnections() / poolMXBean.getTotalConnections();
                    details.put("usageRate", String.format("%.2f%%", usageRate * 100));

                    // 健康状态判断
                    if (usageRate > 0.9) {
                        return Health.down()
                                .withDetails(details)
                                .withDetail("reason", "连接池使用率过高")
                                .build();
                    } else if (poolMXBean.getThreadsAwaitingConnection() > 5) {
                        return Health.down()
                                .withDetails(details)
                                .withDetail("reason", "等待连接的线程过多")
                                .build();
                    } else {
                        return Health.up().withDetails(details).build();
                    }
                } else {
                    return Health.unknown()
                            .withDetail("reason", "数据源不是HikariDataSource类型")
                            .build();
                }
            } catch (Exception e) {
                log.error("HikariCP健康检查失败", e);
                return Health.down()
                        .withDetail("error", e.getMessage())
                        .build();
            }
        }
    }

    /**
     * HikariCP连接池监控器
     */
    @Component
    public static class HikariCPMonitor {

        @Autowired
        private DataSource dataSource;

        /**
         * 定期监控连接池状态
         * 每分钟执行一次
         */
        @Scheduled(fixedRate = 60000)
        public void monitorConnectionPool() {
            try {
                if (dataSource instanceof HikariDataSource) {
                    HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                    HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean();

                    int activeConnections = poolMXBean.getActiveConnections();
                    int idleConnections = poolMXBean.getIdleConnections();
                    int totalConnections = poolMXBean.getTotalConnections();
                    int threadsAwaitingConnection = poolMXBean.getThreadsAwaitingConnection();
                    int maximumPoolSize = hikariDataSource.getMaximumPoolSize();

                    // 计算使用率
                    double usageRate = totalConnections > 0 ? (double) activeConnections / totalConnections : 0;
                    double poolUtilization = (double) totalConnections / maximumPoolSize;

                    // 记录监控日志
                    log.debug("HikariCP连接池状态监控: " +
                            "活跃连接={}, 空闲连接={}, 总连接={}, 最大连接数={}, " +
                            "等待连接线程={}, 使用率={:.2f}%, 池利用率={:.2f}%",
                            activeConnections, idleConnections, totalConnections, maximumPoolSize,
                            threadsAwaitingConnection, usageRate * 100, poolUtilization * 100);

                    // 告警检查
                    checkAndAlert(activeConnections, idleConnections, totalConnections, 
                                threadsAwaitingConnection, maximumPoolSize, usageRate, poolUtilization);
                }
            } catch (Exception e) {
                log.error("连接池监控失败", e);
            }
        }

        /**
         * 检查并发出告警
         */
        private void checkAndAlert(int activeConnections, int idleConnections, int totalConnections,
                                 int threadsAwaitingConnection, int maximumPoolSize, 
                                 double usageRate, double poolUtilization) {
            
            // 连接池使用率告警
            if (usageRate > 0.8) {
                log.warn("⚠️ HikariCP连接池使用率过高: {:.2f}% (活跃连接: {}/{})", 
                        usageRate * 100, activeConnections, totalConnections);
            }

            // 连接池利用率告警
            if (poolUtilization > 0.9) {
                log.warn("⚠️ HikariCP连接池利用率过高: {:.2f}% (总连接: {}/{})", 
                        poolUtilization * 100, totalConnections, maximumPoolSize);
            }

            // 等待连接告警
            if (threadsAwaitingConnection > 0) {
                log.warn("⚠️ 有{}个线程正在等待数据库连接，可能存在连接不足或连接泄漏问题", 
                        threadsAwaitingConnection);
            }

            // 空闲连接过少告警
            if (idleConnections == 0 && totalConnections < maximumPoolSize) {
                log.warn("⚠️ 没有空闲连接且未达到最大连接数，连接池可能需要扩容");
            }

            // 连接数异常告警
            if (totalConnections > maximumPoolSize) {
                log.error("🚨 连接池总连接数({})超过最大连接数({})，存在严重问题！", 
                         totalConnections, maximumPoolSize);
            }
        }

        /**
         * 获取连接池详细状态信息
         */
        public Map<String, Object> getConnectionPoolStatus() {
            Map<String, Object> status = new HashMap<>();
            
            try {
                if (dataSource instanceof HikariDataSource) {
                    HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                    HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean();

                    status.put("poolName", hikariDataSource.getPoolName());
                    status.put("activeConnections", poolMXBean.getActiveConnections());
                    status.put("idleConnections", poolMXBean.getIdleConnections());
                    status.put("totalConnections", poolMXBean.getTotalConnections());
                    status.put("threadsAwaitingConnection", poolMXBean.getThreadsAwaitingConnection());
                    status.put("maximumPoolSize", hikariDataSource.getMaximumPoolSize());
                    status.put("minimumIdle", hikariDataSource.getMinimumIdle());
                    status.put("connectionTimeout", hikariDataSource.getConnectionTimeout());
                    status.put("idleTimeout", hikariDataSource.getIdleTimeout());
                    status.put("maxLifetime", hikariDataSource.getMaxLifetime());
                    status.put("leakDetectionThreshold", hikariDataSource.getLeakDetectionThreshold());

                    // 计算使用率
                    double usageRate = (double) poolMXBean.getActiveConnections() / poolMXBean.getTotalConnections();
                    status.put("usageRate", usageRate);
                    status.put("usageRatePercent", String.format("%.2f%%", usageRate * 100));

                    // 健康状态
                    String healthStatus = "HEALTHY";
                    if (usageRate > 0.9) {
                        healthStatus = "CRITICAL";
                    } else if (usageRate > 0.8) {
                        healthStatus = "WARNING";
                    }
                    status.put("healthStatus", healthStatus);
                    
                    status.put("timestamp", System.currentTimeMillis());
                } else {
                    status.put("error", "数据源不是HikariDataSource类型");
                }
            } catch (Exception e) {
                status.put("error", e.getMessage());
                log.error("获取连接池状态失败", e);
            }
            
            return status;
        }
    }

    /**
     * 连接泄漏检测器
     */
    @Component
    public static class ConnectionLeakDetector {

        @Autowired
        private DataSource dataSource;

        /**
         * 每5分钟检查一次连接泄漏
         */
        @Scheduled(fixedRate = 300000)
        public void detectConnectionLeaks() {
            try {
                if (dataSource instanceof HikariDataSource) {
                    HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
                    
                    // 检查是否启用了连接泄漏检测
                    long leakDetectionThreshold = hikariDataSource.getLeakDetectionThreshold();
                    if (leakDetectionThreshold > 0) {
                        log.debug("连接泄漏检测已启用，阈值: {}ms", leakDetectionThreshold);
                    } else {
                        log.warn("连接泄漏检测未启用，建议在配置中设置leakDetectionThreshold");
                    }

                    // 检查连接池状态
                    HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean();
                    int activeConnections = poolMXBean.getActiveConnections();
                    int totalConnections = poolMXBean.getTotalConnections();

                    // 如果活跃连接数持续很高，可能存在连接泄漏
                    if (activeConnections > totalConnections * 0.8) {
                        log.warn("🔍 检测到可能的连接泄漏: 活跃连接数({})占总连接数({})的{:.1f}%", 
                                activeConnections, totalConnections, 
                                (double) activeConnections / totalConnections * 100);
                    }
                }
            } catch (Exception e) {
                log.error("连接泄漏检测失败", e);
            }
        }
    }
}
